package com.wft.design.gateway.support;

import com.wft.design.common.core.constant.GlobalCacheKey;
import com.wft.design.common.core.util.JsonUtils;
import com.wft.design.system.entity.SysGatewayRoute;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * @author WFT
 * @date 2020/2/5
 * description: 动态路由配置
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class DynamicRouteDefinitionRepository implements RouteDefinitionRepository {

    private final Map<String,RouteDefinition> routes = Collections.synchronizedMap(new HashMap<>());
    private final RedisTemplate<Object,Object> redisTemplate;
    private boolean isInit = true;

    @Override
    public synchronized Flux<RouteDefinition> getRouteDefinitions() {
        if (isInit){
            log.info("正在初始化网关路由配置");
            //  初始化路由,从缓存中获取
            Map<Object, Object> routeMap = this.redisTemplate.opsForHash().entries(GlobalCacheKey.GATEWAY_ROUTE);
            routeMap.values().forEach(obj -> {
                RouteDefinition route = this.build((SysGatewayRoute) obj);
                if (null != route) {
                    routes.put(route.getId(), route);
                }
            });
            log.info("网关路由配置初始化完成");
        }
        isInit = false;
        return Flux.fromIterable(routes.values());
    }

    @Override
    public Mono<Void> save(Mono<RouteDefinition> mono) {
        return mono.flatMap(route -> {
            routes.put(route.getId(), route);
            return Mono.empty();
        });
    }

    @Override
    public Mono<Void> delete(Mono<String> mono) {
        return mono.flatMap(routeId -> {
            routes.remove(routeId);
            return Mono.empty();
        });
    }

    public RouteDefinition build(SysGatewayRoute route){
        try {
            //  构建路由对象
            RouteDefinition definition = new RouteDefinition();
            definition.setId(route.getId().toString());
            definition.setUri(URI.create(route.getUri()));
            definition.setPredicates(JsonUtils.toList(route.getPredicates(), PredicateDefinition.class));
            Assert.notEmpty(definition.getPredicates(), "谓词不能为空");
            definition.setFilters(JsonUtils.toList(route.getFilters(), FilterDefinition.class));
            Assert.notEmpty(definition.getFilters(), "过滤器列表不能为空");
            return definition;
        }catch (Exception e){
            log.error(String.format("路由配置有误: %s",JsonUtils.toJson(route)));
            return null;
        }
    }
}
